﻿using System;
using System.Drawing;
using System.Windows.Forms;
using FadeGameFramework.UI;
using SharpDX;
using SharpDX.Direct2D1;
using SharpDX.DXGI;
using SharpDX.Windows;
using AlphaMode = SharpDX.Direct2D1.AlphaMode;
using Factory = SharpDX.Direct2D1.Factory;

namespace FadeGameFramework
{
    public class Game : IDisposable
    {
        public delegate void RenderDelegate(RenderArgs e);

        public readonly ControlManager ControlManager;

        public readonly DebugDrawer DebugDrawer;

        public readonly Dispatcher Dispatcher;

        public readonly RenderForm Form;

        public readonly GameClock GameClock;

        public readonly InputManager InputManager;

        public readonly IRenderTarget RenderTarget;

        public readonly ResourcesManager ResourcesManager;

        public readonly SpriteManager SpriteManager;

        private readonly WindowRenderTarget windowRenderTarget;

        public Game(int width, int height, string title) {
            Instance = this;

            Form = new RenderForm {
                Size = new Size(width, height),
                StartPosition = FormStartPosition.CenterScreen,
                AutoScaleMode = AutoScaleMode.None,
                Text = title
            };

            //初始化渲染组件
            Factory factory;
            HwndRenderTargetProperties hwndRenderTargetProperties;
            RenderTargetProperties renderTargetProperties;
            InitDirect2D(width, height, out factory, out hwndRenderTargetProperties, out renderTargetProperties);
            windowRenderTarget = new WindowRenderTarget(factory, renderTargetProperties, hwndRenderTargetProperties);

            //初始化所有组件
            InputManager = new InputManager();
            ResourcesManager = new ResourcesManager(windowRenderTarget);
            GameClock = new GameClock();
            Dispatcher = new Dispatcher();
            SpriteManager = new SpriteManager();
            DebugDrawer = new DebugDrawer(windowRenderTarget);
            RenderTarget = new RenderTargetDx(windowRenderTarget);
            ControlManager = new ControlManager(RenderTarget);

            //为需要更新的组件添加更新关联
            Dispatcher.Schedule(InputManager.Update);
            Dispatcher.Schedule(DebugDrawer.Update, 0.4f);
        }

        public static Game Instance { get; private set; }

        public void Dispose() {
            if (!windowRenderTarget.IsDisposed) {
                windowRenderTarget.Dispose();
            }
        }

        public event RenderDelegate OnRender;

        public void Run() {
            RenderLoop.Run(Form, GameLoop);
        }

        private void GameLoop() {
            //FIXME 用上一帧的时间预测下一帧的时间可能会导致帧率抖动

            //开始计时
            GameClock.Start();
            //更新所有需要更新的组件
            Dispatcher.Update(GameClock.DeltaTime);
            //绘图
            windowRenderTarget.BeginDraw();
            OnRender?.Invoke(new RenderArgs(GameClock.DeltaTime, RenderTarget));
            windowRenderTarget.EndDraw();
            //停止计时
            GameClock.StopAndReset();
        }

        private void InitDirect2D(int width, int height, out Factory factory,
            out HwndRenderTargetProperties hwndRenderTargetProperties,
            out RenderTargetProperties renderTargetProperties) {
            factory = new Factory(FactoryType.SingleThreaded);
            hwndRenderTargetProperties = new HwndRenderTargetProperties {
                Hwnd = Form.Handle,
                PixelSize = new Size2(Form.Width, Form.Height),
                PresentOptions = PresentOptions.RetainContents
            };
            var pixelFormat = new PixelFormat(Format.B8G8R8A8_UNorm, AlphaMode.Ignore);
            renderTargetProperties = new RenderTargetProperties(
                RenderTargetType.Hardware, pixelFormat, 0, 0, RenderTargetUsage.None, FeatureLevel.Level_DEFAULT);
        }
    }
}